﻿#region using...
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
#endregion

namespace Infusion.Silverlight.Controls.Ribbon
{
  #region : RibbonTab :
  #region Template Parts...
  [TemplatePart(Name = RibbonTab.RibbonTabLayoutRoot, Type = typeof(Canvas))]
  [TemplatePart(Name = RibbonTab.TxtTitle, Type = typeof(TextBlock))]
  [TemplatePart(Name = RibbonTab.GridText, Type = typeof(Grid))]
  [TemplatePart(Name = RibbonTab.PathCanvasClipFigure, Type = typeof(PathFigure))]
  [TemplatePart(Name = RibbonTab.PathOuterBorder, Type = typeof(Path))]
  [TemplatePart(Name = RibbonTab.PathOuterBorderFigure, Type = typeof(PathFigure))]
  [TemplatePart(Name = RibbonTab.PathInnerBorder, Type = typeof(Path))]
  [TemplatePart(Name = RibbonTab.PathInnerBorderFigure, Type = typeof(PathFigure))]
  [TemplatePart(Name = RibbonTab.StoryboardTabHighlight, Type = typeof(Storyboard))]
  [TemplatePart(Name = RibbonTab.StoryboardTabHighlightSelected, Type = typeof(Storyboard))]
  #endregion
  [ContentProperty("Groups")]
  public class RibbonTab : Control
  {
    #region Constants...
    private const double tabPadding = 28;
    #endregion

    #region TemplatePart Names...
    public const string RibbonTabLayoutRoot = "RibbonTabLayoutRoot";
    public const string TxtTitle = "TxtTitle";
    public const string GridText = "GridText";
    public const string PathCanvasClipFigure = "PathCanvasClipFigure";
    public const string PathOuterBorder = "PathOuterBorder";
    public const string PathOuterBorderFigure = "PathOuterBorderFigure";
    public const string PathInnerBorder = "PathInnerBorder";
    public const string PathInnerBorderFigure = "PathInnerBorderFigure";
    public const string StoryboardTabHighlight = "StoryboardTabHighlight";
    public const string StoryboardTabHighlightSelected = "StoryboardTabHighlightSelected";
    #endregion

    #region TemplatePart Variables...
    private Canvas ribbonTabLayoutRoot;
    private TextBlock txtTitle;
    private Grid gridText;
    private PathFigure pathCanvasClipFigure;
    private Path pathOuterBorder;
    private PathFigure pathOuterBorderFigure;
    private Path pathInnerBorder;
    private PathFigure pathInnerBorderFigure;
    private Storyboard storyboardTabHighlight;
    private Storyboard storyboardTabHighlightSelected;
    #endregion

    #region Class Variables...
    private Ribbon parentRibbon;
    private bool textLayoutUpdated = false;
    private bool mouseOver = false;
    private bool selected = false;
    private bool hasLoaded = false;
    private LinearGradientBrush tabSelectedBrush;
    private LinearGradientBrush tabHoverBrush;
    #endregion

    #region Dependency Properties...
    #region GroupsProperty
    /// <summary>
    /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonTab.Groups dependency property.
    /// </summary>
    public static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
            "Groups",
            typeof(RibbonTabGroupCollection),
            typeof(RibbonTab),
            null);
    #endregion

    #region TitleProperty
    /// <summary>
    /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonTab.Title dependency property.
    /// </summary>
    public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            "Title",
            typeof(string),
            typeof(RibbonTab),
            new PropertyMetadata(new PropertyChangedCallback(TitlePropertyChanged)));
    #endregion
    #endregion

    #region Dependency Property Changed Handlers...
    #region TitlePropertyChanged
    private static void TitlePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
      if (args.NewValue != null)
      {
        RibbonTab tab = (RibbonTab)obj;
        tab.SetText(args.NewValue.ToString());
      }
      else
      {
        throw new ArgumentNullException("Title can not be null or an empty string.");
      }
    }
    #endregion
    #endregion

    #region Constructor(s)...
    #region RibbonTab
    public RibbonTab()
      : base()
    {
      DefaultStyleKey = typeof(RibbonTab);

      Groups = new RibbonTabGroupCollection();
      Groups.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Groups_CollectionChanged);

      //tabSelectedBrush...
      Dictionary<double, Color> tabSelectedBrushGradientStops = new Dictionary<double, Color>();
      tabSelectedBrushGradientStops.Add(0.0, Helper.HexToColor("#F5F6F6"));
      tabSelectedBrushGradientStops.Add(0.5, Helper.HexToColor("#EAEDF2"));
      tabSelectedBrushGradientStops.Add(1.0, Helper.HexToColor("#ECEFF4"));

      tabSelectedBrush = new LinearGradientBrush();
      tabSelectedBrush.StartPoint = new Point(0.5, 0);
      tabSelectedBrush.EndPoint = new Point(0.5, 1);
      tabSelectedBrush.GradientStops = Helper.CreateGradientStopCollection(tabSelectedBrushGradientStops);

      //tabHoverBrush...
      Dictionary<double, Color> tabHoverBrushGradientStops = new Dictionary<double, Color>();
      tabHoverBrushGradientStops.Add(0.0, Helper.HexToColor("#D5D5D6"));
      tabHoverBrushGradientStops.Add(0.5, Helper.HexToColor("#E8E5DC"));
      tabHoverBrushGradientStops.Add(1.0, Helper.HexToColor("#E7CF98"));

      tabHoverBrush = new LinearGradientBrush();
      tabHoverBrush.StartPoint = new Point(0.5, 0);
      tabHoverBrush.EndPoint = new Point(0.5, 1);
      tabHoverBrush.GradientStops = Helper.CreateGradientStopCollection(tabHoverBrushGradientStops);
    }
    #endregion
    #endregion

    #region Event Handlers...
    #region ribbonTabLayoutRoot_LayoutUpdated
    private void ribbonTabLayoutRoot_LayoutUpdated(object sender, EventArgs e)
    {
      if (!textLayoutUpdated)
      {
        SetPathFigures();
        textLayoutUpdated = true;
      }
    }
    #endregion

    #region ribbonTabLayoutRoot_MouseLeave
    private void ribbonTabLayoutRoot_MouseLeave(object sender, MouseEventArgs e)
    {
      mouseOver = false;
      BlurTab();
    }
    #endregion

    #region ribbonTabLayoutRoot_MouseEnter
    private void ribbonTabLayoutRoot_MouseEnter(object sender, MouseEventArgs e)
    {
      mouseOver = true;
      FocusTab();
    }
    #endregion

    #region ribbonTabLayoutRoot_MouseLeftButtonDown
    private void ribbonTabLayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
      parentRibbon.SelectedTabIndex = parentRibbon.Tabs.IndexOf(this);
    }
    #endregion

    #region Groups_CollectionChanged
    private void Groups_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
      switch (e.Action)
      {
        case NotifyCollectionChangedAction.Add:
          foreach (RibbonTabGroup group in e.NewItems)
          {
            group.ParentRibbonTab = this;
          }
          break;
        case NotifyCollectionChangedAction.Remove:
          break;
        case NotifyCollectionChangedAction.Replace:
          break;
        case NotifyCollectionChangedAction.Reset:
          break;
        default:
          break;
      }
    }
    #endregion
    #endregion

    #region Methods...
    #region SetPathFigures
    private void SetPathFigures()
    {
      ribbonTabLayoutRoot.Width = txtTitle.ActualWidth + tabPadding;
      gridText.ColumnDefinitions[0].Width = new GridLength(txtTitle.ActualWidth + tabPadding);

      pathCanvasClipFigure.StartPoint = new Point(selected ? 0 : 2.5, selected ? 23 : 22);
      pathCanvasClipFigure.Segments = GenerateBorderSegments(txtTitle.ActualWidth + tabPadding, false);

      pathOuterBorderFigure.StartPoint = new Point(selected ? 0 : 2.5, 22.5);
      pathOuterBorderFigure.Segments = GenerateBorderSegments(txtTitle.ActualWidth + tabPadding, false);

      pathInnerBorderFigure.StartPoint = new Point(selected ? 0 : 2.5, 22.5);
      pathInnerBorderFigure.Segments = GenerateBorderSegments(txtTitle.ActualWidth + tabPadding - 2, false);
    }
    #endregion

    #region BlurTab
    internal void BlurTab()
    {
      if (!ParentRibbon.HasMenuOpen)
      {
        if (selected)
        {
          storyboardTabHighlightSelected.Begin();

          txtTitle.Foreground = new SolidColorBrush(Helper.HexToColor("#666666"));
        }
        else
        {
          pathInnerBorder.Visibility = Visibility.Collapsed;
          pathOuterBorder.Visibility = Visibility.Collapsed;

          storyboardTabHighlight.Begin();

          txtTitle.Foreground = new SolidColorBrush(Helper.HexToColor("#EFF1F3"));
        }
      }
    }
    #endregion

    #region FocusTab
    internal void FocusTab()
    {
      if (!ParentRibbon.HasMenuOpen)
      {
        if (selected)
        {
          storyboardTabHighlightSelected.Stop();

          pathOuterBorder.Stroke = new SolidColorBrush(Helper.HexToColor("#FED15E"));
          pathOuterBorder.StrokeThickness = 3;
          pathOuterBorder.Opacity = 0.6;

          txtTitle.Foreground = new SolidColorBrush(Helper.HexToColor("#666666"));
        }
        else
        {
          storyboardTabHighlight.Stop();

          tabHoverBrush.GradientStops[0].Color = Helper.HexToColor("#D5D5D6");
          tabHoverBrush.GradientStops[1].Color = Helper.HexToColor("#E8E5DC");
          tabHoverBrush.GradientStops[2].Color = Helper.HexToColor("#E7CF98");

          ribbonTabLayoutRoot.Background = tabHoverBrush;
          pathInnerBorder.Visibility = Visibility.Visible;
         pathOuterBorder.Visibility = Visibility.Visible;

          txtTitle.Foreground = new SolidColorBrush(Helper.HexToColor("#666666"));
        }
      }
    }
    #endregion

    #region GenerateBorderSegments
    private PathSegmentCollection GenerateBorderSegments(double width, bool extraHeight)
    {
      PathSegmentCollection segments = new PathSegmentCollection();

      if (extraHeight) segments.Add(Helper.GenerateLineSegment(0, 22.5));
      if (selected) segments.Add(Helper.GenerateArcSegment(SweepDirection.Counterclockwise, 2.5, 20, 2.5, 2.5));
      segments.Add(Helper.GenerateLineSegment(2.5, 2.5));
      segments.Add(Helper.GenerateArcSegment(SweepDirection.Clockwise, 5, 0, 2.5, 2.5));
      segments.Add(Helper.GenerateLineSegment(width - 5, 0));
      segments.Add(Helper.GenerateArcSegment(SweepDirection.Clockwise, width - 2.5, 2.5, 2.5, 2.5));
      segments.Add(Helper.GenerateLineSegment(width - 2.5, 20 + (Selected ? 0 : 2.5)));
      if (selected) segments.Add(Helper.GenerateArcSegment(SweepDirection.Counterclockwise, width, 22.5, 2.5, 2.5));
      if (extraHeight) segments.Add(Helper.GenerateLineSegment(width, 23));

      return segments;
    }
    #endregion

    #region OnApplyTemplate
    public override void OnApplyTemplate()
    {
      base.OnApplyTemplate();

      ribbonTabLayoutRoot = (Canvas)GetTemplateChild(RibbonTabLayoutRoot);
      txtTitle = (TextBlock)GetTemplateChild(TxtTitle);
      gridText = (Grid)GetTemplateChild(GridText);
      pathCanvasClipFigure = (PathFigure)GetTemplateChild(PathCanvasClipFigure);
      pathOuterBorder = (Path)GetTemplateChild(PathOuterBorder);
      pathOuterBorderFigure = (PathFigure)GetTemplateChild(PathOuterBorderFigure);
      pathInnerBorder = (Path)GetTemplateChild(PathInnerBorder);
      pathInnerBorderFigure = (PathFigure)GetTemplateChild(PathInnerBorderFigure);
      storyboardTabHighlight = (Storyboard)GetTemplateChild(StoryboardTabHighlight);
      storyboardTabHighlightSelected = (Storyboard)GetTemplateChild(StoryboardTabHighlightSelected);

      ribbonTabLayoutRoot.LayoutUpdated += new EventHandler(ribbonTabLayoutRoot_LayoutUpdated);
      ribbonTabLayoutRoot.MouseEnter += new MouseEventHandler(ribbonTabLayoutRoot_MouseEnter);
      ribbonTabLayoutRoot.MouseLeave += new MouseEventHandler(ribbonTabLayoutRoot_MouseLeave);
      ribbonTabLayoutRoot.MouseLeftButtonDown += new MouseButtonEventHandler(ribbonTabLayoutRoot_MouseLeftButtonDown);

      txtTitle.Text = Title;

      if (selected)
      {
        ribbonTabLayoutRoot.Background = tabSelectedBrush;
        pathOuterBorder.Visibility = Visibility.Visible;

        txtTitle.Foreground = new SolidColorBrush(Helper.HexToColor("#666666"));
      }
      else
      {
        txtTitle.Foreground = new SolidColorBrush(Helper.HexToColor("#EFF1F3"));
      }

      for (int groupIndex = 0; groupIndex < Groups.Count; groupIndex++)
      {
        if (parentRibbon.TabContentDictionary[this].ColumnDefinitions.Count - 1 < groupIndex)
          parentRibbon.TabContentDictionary[this].ColumnDefinitions.Add(Helper.CreateGridColumnDefinition(0, GridUnitType.Auto));

        Groups[groupIndex].SetValue(Grid.ColumnProperty, groupIndex);
        Groups[groupIndex].SetValue(Grid.RowProperty, 0);

        parentRibbon.TabContentDictionary[this].Children.Add(Groups[groupIndex]);
      }
    }
    #endregion

    #region SetText
    private void SetText(string title)
    {
      textLayoutUpdated = false;
      if (txtTitle != null)
        txtTitle.Text = Title;
    }
    #endregion
    #endregion

    #region Properties...
    #region Groups
    public RibbonTabGroupCollection Groups
    {
      get { return (RibbonTabGroupCollection)GetValue(GroupsProperty); }
      set { SetValue(GroupsProperty, value); }
    }
    #endregion

    #region Selected
    internal bool Selected
    {
      get
      {
        return selected;
      }
      set
      {
        selected = value;
        SetPathFigures();

        if (selected)
        {
          ribbonTabLayoutRoot.Background = tabSelectedBrush;
          pathInnerBorder.Visibility = Visibility.Collapsed;
          pathOuterBorder.Visibility = Visibility.Visible;
          parentRibbon.TabContentDictionary[this].Visibility = Visibility.Visible;

          txtTitle.Foreground = new SolidColorBrush(Helper.HexToColor("#666666"));

        }
        else
        {
          ribbonTabLayoutRoot.Background = new SolidColorBrush(Colors.Transparent);
          pathInnerBorder.Visibility = Visibility.Collapsed;
          pathOuterBorder.Visibility = Visibility.Collapsed;
          parentRibbon.TabContentDictionary[this].Visibility = Visibility.Collapsed;

          txtTitle.Foreground = new SolidColorBrush(Helper.HexToColor("#EFF1F3"));

        }

        if (mouseOver)
          FocusTab();
      }
    }
    #endregion

    #region HasLoaded
    public bool HasLoaded
    {
      get { return hasLoaded; }
      internal set { hasLoaded = value; }
    }
    #endregion

    #region ParentRibbon
    public Ribbon ParentRibbon
    {
      get { return parentRibbon; }
      set { parentRibbon = value; }
    }
    #endregion

    #region Title
    public string Title
    {
      get { return (string)GetValue(TitleProperty); }
      set { SetValue(TitleProperty, value); }
    }
    #endregion
    #endregion
  }
  #endregion

  #region : RibbonTabGroupCollection :
  public class RibbonTabGroupCollection : ObservableCollection<RibbonTabGroup>
  {
  }
  #endregion
}